<?php

/*
 * Copyright 2011 Google Inc.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

defined( '_JEXEC' ) or die( 'Restricted access' ); 
require_once( JApplicationHelper::getPath( 'admin_html' ) ); 
jimport('joomla.filesystem.file');

//Defines the maximum file size for each video sitemap file
define("MAX_FILE_SIZE",9500000);
//Defines the maximum number of videos that each video sitemap files could have
define("MAX_NUMBER_VIDEOS",9000);
//Defines the pattern of the files names for the video sitemaps
define("VIDEOSITEMAP_FILEPATTERN","videositemaps_");
//Defines the name of the fail that holds the information about the updates
define("UPDATE_FILE_STATS","videositemaps.stats");
//Defines the url of the Google Webmaster tool ping service
define('VIDEOSITEMAP_PING', 'www.google.com/webmasters/tools/ping?sitemap=');

switch($task) {
	case 'build': 
		$post = JRequest::get('post');
		PROCESS_videositemapgenerator::build( $option, ( ( isset($post['force']) ) ? true : false ));
		
	default: 
		PROCESS_videositemapgenerator::listSitemaps( $option );
		break;
}


class PROCESS_videositemapgenerator{
	/**
	 * Executes the list process for showing the video sitemap files on the admin screen
	 * @param mixed $option Obtion sent from the post
	 */
	function listSitemaps( $option ){
		$files = self::searchSitemaps();
		HTML_videositemapgenerator::listSitemaps( $option , $files);
	}
	
	/**
	 * Executes the build process to (re)create the video sitemap files
	 * @param mixed $option Option sent from the post
	 * @param Boolean $force Tells the process to rebuild the files anyway 
	 */
	function build( $option , $force ){
		$checkData = self::obtainVideos( true );
		
		if( self::checkUpdate($force , $checkData) ){
			$data = self::obtainVideos( false, $checkData );
			$result = array();
			$result['final'] = "<h3>Build process successful</h3>";
			if(is_array($data) && !empty($data)){
				$result['clear'] = self::clear();
				$result['final'] .= "<h4>" .implode("<br/>",self::createFiles( $data )) . "</h4>";
			}
			else{
				$result['final'] = "<h3 style='color:red;'>Build process ommited. No new changes detected to rebuild the sitemaps.</h3>";
			}
		}
		else{
			$result['clear'] = 0;
			$result['final'] = "<h3>Build process skipped. There are no chamges since last update.</h3>";
		}
		HTML_videositemapgenerator::build( $option , $result);
	}
	
	/**
	 * Searches in the root of the site for video sitemap files
	 */
	function searchSitemaps(){
		$files = JFolder::files(JPATH_ROOT, $filter = VIDEOSITEMAP_FILEPATTERN, $recurse=false, $fullpath=false );
		if( !empty($files) ){
			foreach($files as $k => $f){
				$resId = fopen(JPATH_ROOT . DS . $f,'r');
				$fileStats=fstat($resId);
				fclose($resId);
				$file = array();
				$file['name'] = $f;
				$file['size'] = $fileStats['size'];
				$file['mtime'] = date("m/d/Y H:i:s",$fileStats['mtime']);
				$files[$k] = $file;
			}
		}
		return $files;
	}
	
	/**
	 * Cheks if the sitemap files need update
	 * @param Boolean $force Tells the process to rebuild the files anyway
	 * @param Array $rows Array containing the video content to rebuild the sitemaps, in where the process checks the updates
	 */
	function checkUpdate( $force , $rows ){
		$needsUpdate = false;
		
		if(!$force){
			$count = 0;
			$ids = array();
			for($i=0 , $n = count($rows) ; $i < $n; $i++){
				$row = $rows[$i];
				$videoContent = self::parseVideo( $row , false );
				if(
					$videoContent['article'] != '' &&
					$videoContent['title'] != '' &&
					$videoContent['v_info'] != '' &&
					$videoContent['video'] != '' &&
					$videoContent['thumbnail'] != ''
				){
					$count++;
					$ids[] = $videoContent['article'];
				}
				
			}
			
			if( JFile::exists(JPATH_ROOT . DS . UPDATE_FILE_STATS) ){
				$content = explode( "\n" , JFile::read( JPATH_ROOT . DS . UPDATE_FILE_STATS ) );
				
				if( !empty($ids) ){
					$ids = md5( implode( ":" , $ids ) );
					if( $content[0] != $count || $content[1] != $ids){
						$needsUpdate = true;
						JFile::write(JPATH_ROOT . DS . UPDATE_FILE_STATS,$count . "\n" . $ids);
					}
				}
			}
			else{
				$needsUpdate = true;
				JFile::write(JPATH_ROOT . DS . UPDATE_FILE_STATS,$count . "\n" . $ids);
			}
		}
		else{
			$needsUpdate = true;
		}
		
		return $needsUpdate;
	}
	
	/**
	 * Obtains all video content from the site databases'
	 * @param Boolean $dataOnly Indicates the process to return just the data withut format
	 * @param Array $rows Array containing the video content to rebuild the sitemaps, in case it has been obtained previously
	 */
	function obtainVideos( $dataOnly=false, $rows=null ) {
		if(!$rows){
			$db =& JFactory::getDBO(); 
			$query = "SELECT id, title, alias, introtext, catid, UNIX_TIMESTAMP(created) as 'created'
				FROM #__content
				WHERE catid = (
				SELECT id
				FROM #__categories
				WHERE title = 'Video' )  
				ORDER BY id"; 
			$db->setQuery( $query ); 
			$rows = $db->loadObjectList(); 
			if ($db->getErrorNum()) {
				echo $db->stderr(); 
				return false;
			} 
			
			if($dataOnly){
				return $rows;	
			}	
		}
		
		$videoString = "<videos>";
		$size = 100;
		$count = 0;
		$videoContent = array();
		$kFile = 1;
		for($i=0, $n=count($rows); $i < $n; $i++){
			$row = $rows[$i]; 
			$videoData = self::parseVideo( $row );
			if($videoData != null){
				$videoString .= $videoData;
				$size += 2500;
				$count++;
			}
			
			if($size > MAX_FILE_SIZE || $count > MAX_NUMBER_VIDEOS || $i == ($n - 1)){
				$videoContent[$kFile]['data'] = $videoString . "</videos>";
				$videoContent[$kFile]['count'] = $count;
				$kFile++;
				$videoString = "<videos>";
				$size = 100;
				$count = 0;
			}
		}
		return $videoContent;
	}
	
	/**
	 * Parses the video data from the database records and estructures it in a data array
	 * @param Object $row Row object obtained from the database
	 * @param Boolean $format Indicates if the format process must be executed after the array transformation
	 */
	function parseVideo( $row , $format = true ){
		$tmpVideoData = explode('<br />',$row->introtext);
		$videoData = array();
		$videoData['article'] = $row->id;
		$videoData['title'] = $row->title;
		$videoData['alias'] = $row->alias;
		$videoData['catid'] = $row->catid;
		$videoData['created'] = $row->created;
		foreach($tmpVideoData as $k => $vd){
			if($vd != ''){
				$tmpData = explode("::",$vd);
				$videoData[$tmpData[1]] = $tmpData[2];
			}	
		}
		if( $format ){
			return self::formatData( $videoData );	
		}
		return $videoData;
	}
	
	/**
	 * Formats each video array component in a XML string
	 * @param Array $video Array component containig all the info needed by the formatter
	 */
	function formatData( $video ){
		$result = null;
		if(
			$video['article'] != '' &&
			$video['title'] != '' &&
			$video['v_info'] != '' &&
			$video['video'] != '' &&
			$video['thumbnail'] != ''
		){
			$result = '<video>';
				$result .= '<url>' . JURI::root() . 'index.php?view=article&amp;id=' . $video['article'] . '</url>';
				$result .= '<title>' . $video['title'] . '</title>';
				$result .= '<description>' . $video['v_info'] . '</description>';
				$result .= '<file>' . JURI::root() . $video['video'] . '</file>';
				$result .= '<image>' . JURI::root() . $video['thumbnail'] . '</image>';
				$result .= '<publication_date>' . date(DATE_ATOM , $video['created']) . '</publication_date>';
			
		    if($video['expiration_date'] != ''){
					$exp_date = explode('/' , $video['expiration_date']);
					$exp_date = date(DATE_ATOM , mktime(23 , 59 , 59 , $exp_date[0] , $exp_date[1] , $exp_date[2]));
		    	$result .= '<expiration>' . $exp_date . '</expiration>';
				}
				
				if($video['duration'] != ''){
					$result .= '<duration>' . $video['duration'] . '</duration>';
				}
				
				if($video['regional_restrictions'] != ''){
					$result .= '<restrictions>' . $video['regional_restrictions'] . '</restrictions>';
				}
				
				if(trim($video['family_friendly_content']) != ''){
					$result .= '<family_friendly>YES</family_friendly>';
				}
				
				if($video['video_category'] != ''){
					$result .= '<category>' . $video['video_category'] . '</category>';
				
				}
				if($video['tags'] != ''){
					$result .= '<tags><tag>';
					$result .= implode('</tag><tag>' , explode(',' , $video['tags'] ));
					$result .= '</tag></tags>';
				}
				$result .= '</video>';
		}
		return $result;
	}
	
	/**
	 * Deletes all video sitemap files before rebuilding them
	 */
	function clear(){
		$files = self::searchSitemaps();
		$deleted = 0;
		foreach($files as $k => $f){
			$deleted++;
			JFile::delete( JPATH_ROOT . DS . $f['name']);
		}
		return $deleted;
	}
	
	/**
	 * Creates the video sitemap files taking into account the size and quantity restrictions
	 * @param Array $videos Array containing the video content information for rebuilding each of the video sitemap files
	 */
	function createFiles( $videos ){
		$ret = null;
		if(is_array($videos) && !empty($videos)){
			$xslDoc = simplexml_load_file(JPATH_COMPONENT . DS . "videositemapgenerator.xsl");
			$xsl = new XSLTProcessor();
			$xsl->importStylesheet($xslDoc);
			
			foreach($videos as $k => $vs){
				$xmlData	= simplexml_load_string( $vs['data'] );
		  	$xmlFile	= $xsl->transformToXML($xmlData); 
		  	$file = VIDEOSITEMAP_FILEPATTERN . str_pad( $k ,4,'0',STR_PAD_LEFT) . '.xml';
				JFile::write(JPATH_ROOT . DS . $file , $xmlFile);
				$ret[] = $file . ": File created. Video count: " . $vs['count'] . ". " . self::ping($file);
			}
		}
		return $ret;	
	}
	
	/**
	 * Pings Google Webmaster tool with the sitemap updated
	 */
	function ping($file){
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, VIDEOSITEMAP_PING . JURI::root() . $file);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$output = curl_exec($ch);
		curl_close($ch);
		if(strpos($output,'<h2>Sitemap Notification Received</h2>') !== false){
			return " - Sitemap Notification Received";
		}
		return " - Sitemap Notification Error";
	}
}

